home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / win / tkWinScrlbr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  19.0 KB  |  746 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkWinScrollbar.c --
  3.  *
  4.  *    This file implements the Windows specific portion of the scrollbar
  5.  *    widget.
  6.  *
  7.  * Copyright (c) 1996 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkWinScrlbr.c 1.19 97/08/13 17:37:49
  13.  */
  14.  
  15. #include "tkWinInt.h"
  16. #include "tkScrollbar.h"
  17.  
  18.  
  19. /*
  20.  * The following constant is used to specify the maximum scroll position.
  21.  * This value is limited by the Win32 API to either 16-bits or 32-bits,
  22.  * depending on the context.  For now we'll just use a value small
  23.  * enough to fit in 16-bits, but which gives us 4-digits of precision.
  24.  */
  25.  
  26. #define MAX_SCROLL 10000
  27.  
  28. /*
  29.  * Declaration of Windows specific scrollbar structure.
  30.  */
  31.  
  32. typedef struct WinScrollbar {
  33.     TkScrollbar info;        /* Generic scrollbar info. */
  34.     WNDPROC oldProc;        /* Old window procedure. */
  35.     int lastVertical;        /* 1 if was vertical at last refresh. */
  36.     HWND hwnd;            /* Current window handle. */
  37.     int winFlags;        /* Various flags; see below. */
  38. } WinScrollbar;
  39.  
  40. /*
  41.  * Flag bits for native scrollbars:
  42.  * 
  43.  * IN_MODAL_LOOP:        Non-zero means this scrollbar is in the middle
  44.  *                of a modal loop.
  45.  * ALREADY_DEAD:        Non-zero means this scrollbar has been
  46.  *                destroyed, but has not been cleaned up.
  47.  */
  48.  
  49. #define IN_MODAL_LOOP    1
  50. #define ALREADY_DEAD    2
  51.  
  52. /*
  53.  * Cached system metrics used to determine scrollbar geometry.
  54.  */
  55.  
  56. static int initialized = 0;
  57. static int hArrowWidth, hThumb; /* Horizontal control metrics. */
  58. static int vArrowWidth, vArrowHeight, vThumb; /* Vertical control metrics. */
  59.  
  60. /*
  61.  * This variable holds the default width for a scrollbar in string
  62.  * form for use in a Tk_ConfigSpec.
  63.  */
  64.  
  65. static char defWidth[8];
  66.  
  67. /*
  68.  * Declarations for functions defined in this file.
  69.  */
  70.  
  71. static Window        CreateProc _ANSI_ARGS_((Tk_Window tkwin,
  72.                 Window parent, ClientData instanceData));
  73. static void        ModalLoopProc _ANSI_ARGS_((Tk_Window tkwin,
  74.                 XEvent *eventPtr));
  75. static int        ScrollbarBindProc _ANSI_ARGS_((ClientData clientData,
  76.                 Tcl_Interp *interp, XEvent *eventPtr,
  77.                 Tk_Window tkwin, KeySym keySym));
  78. static LRESULT CALLBACK    ScrollbarProc _ANSI_ARGS_((HWND hwnd, UINT message,
  79.                 WPARAM wParam, LPARAM lParam));
  80. static void        UpdateScrollbar _ANSI_ARGS_((
  81.                     WinScrollbar *scrollPtr));
  82. static void        UpdateScrollbarMetrics _ANSI_ARGS_((void));
  83.  
  84. /*
  85.  * The class procedure table for the scrollbar widget.
  86.  */
  87.  
  88. TkClassProcs tkpScrollbarProcs = {
  89.     CreateProc,            /* createProc */
  90.     NULL,            /* geometryProc */
  91.     ModalLoopProc,        /* modalProc */
  92. };
  93.  
  94.  
  95. /*
  96.  *----------------------------------------------------------------------
  97.  *
  98.  * TkpCreateScrollbar --
  99.  *
  100.  *    Allocate a new TkScrollbar structure.
  101.  *
  102.  * Results:
  103.  *    Returns a newly allocated TkScrollbar structure.
  104.  *
  105.  * Side effects:
  106.  *    Registers an event handler for the widget.
  107.  *
  108.  *----------------------------------------------------------------------
  109.  */
  110.  
  111. TkScrollbar *
  112. TkpCreateScrollbar(tkwin)
  113.     Tk_Window tkwin;
  114. {
  115.     WinScrollbar *scrollPtr;
  116.     TkWindow *winPtr = (TkWindow *)tkwin;
  117.     
  118.     if (!initialized) {
  119.     UpdateScrollbarMetrics();
  120.     initialized = 1;
  121.     }
  122.  
  123.     scrollPtr = (WinScrollbar *) ckalloc(sizeof(WinScrollbar));
  124.     scrollPtr->winFlags = 0;
  125.     scrollPtr->hwnd = NULL;
  126.  
  127.     Tk_CreateEventHandler(tkwin,
  128.         ExposureMask|StructureNotifyMask|FocusChangeMask,
  129.         TkScrollbarEventProc, (ClientData) scrollPtr);
  130.  
  131.     if (!Tcl_GetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL)) {
  132.     Tcl_SetAssocData(winPtr->mainPtr->interp, "TkScrollbar", NULL,
  133.         (ClientData)1);
  134.     TkCreateBindingProcedure(winPtr->mainPtr->interp,
  135.         winPtr->mainPtr->bindingTable,
  136.         (ClientData)Tk_GetUid("Scrollbar"), "<ButtonPress>",
  137.         ScrollbarBindProc, NULL, NULL);
  138.     }
  139.  
  140.     return (TkScrollbar*) scrollPtr;
  141. }
  142.  
  143. /*
  144.  *----------------------------------------------------------------------
  145.  *
  146.  * UpdateScrollbar --
  147.  *
  148.  *    This function updates the position and size of the scrollbar
  149.  *    thumb based on the current settings.
  150.  *
  151.  * Results:
  152.  *    None.
  153.  *
  154.  * Side effects:
  155.  *    Moves the thumb.
  156.  *
  157.  *----------------------------------------------------------------------
  158.  */
  159.  
  160. static void
  161. UpdateScrollbar(scrollPtr)
  162.     WinScrollbar *scrollPtr;
  163. {
  164.     SCROLLINFO scrollInfo;
  165.     double thumbSize;
  166.  
  167.     /*
  168.      * Update the current scrollbar position and shape.
  169.      */
  170.  
  171.     scrollInfo.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;
  172.     scrollInfo.cbSize = sizeof(scrollInfo);
  173.     scrollInfo.nMin = 0;
  174.     scrollInfo.nMax = MAX_SCROLL;
  175.     thumbSize = (scrollPtr->info.lastFraction - scrollPtr->info.firstFraction);
  176.     if (tkpIsWin32s) {
  177.     scrollInfo.nPage = 0;
  178.     } else {
  179.     scrollInfo.nPage = ((UINT) (thumbSize * (double) MAX_SCROLL)) + 1;
  180.     } 
  181.     if (thumbSize < 1.0) {
  182.     scrollInfo.nPos = (int)
  183.         ((scrollPtr->info.firstFraction / (1.0-thumbSize))
  184.             * (MAX_SCROLL - (scrollInfo.nPage - 1)));
  185.     } else {
  186.     scrollInfo.nPos = 0;
  187.     }
  188.     SetScrollInfo(scrollPtr->hwnd, SB_CTL, &scrollInfo, TRUE);
  189. }
  190.  
  191. /*
  192.  *----------------------------------------------------------------------
  193.  *
  194.  * CreateProc --
  195.  *
  196.  *    This function creates a new Scrollbar control, subclasses
  197.  *    the instance, and generates a new Window object.
  198.  *
  199.  * Results:
  200.  *    Returns the newly allocated Window object, or None on failure.
  201.  *
  202.  * Side effects:
  203.  *    Causes a new Scrollbar control to come into existence.
  204.  *
  205.  *----------------------------------------------------------------------
  206.  */
  207.  
  208. static Window
  209. CreateProc(tkwin, parentWin, instanceData)
  210.     Tk_Window tkwin;        /* Token for window. */
  211.     Window parentWin;        /* Parent of new window. */
  212.     ClientData instanceData;    /* Scrollbar instance data. */
  213. {
  214.     DWORD style;
  215.     Window window;
  216.     HWND parent;
  217.     TkWindow *winPtr;
  218.     WinScrollbar *scrollPtr = (WinScrollbar *)instanceData;
  219.  
  220.     parent = Tk_GetHWND(parentWin);
  221.  
  222.     if (scrollPtr->info.vertical) {
  223.     style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
  224.         | SBS_VERT | SBS_RIGHTALIGN;
  225.     } else {
  226.     style = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS
  227.         | SBS_HORZ | SBS_BOTTOMALIGN;
  228.     }
  229.  
  230.     scrollPtr->hwnd = CreateWindow("SCROLLBAR", NULL, style,
  231.         Tk_X(tkwin), Tk_Y(tkwin), Tk_Width(tkwin), Tk_Height(tkwin),
  232.         parent, NULL, Tk_GetHINSTANCE(), NULL);
  233.  
  234.     /*
  235.      * Ensure new window is inserted into the stacking order at the correct
  236.      * place. 
  237.      */
  238.  
  239.     SetWindowPos(scrollPtr->hwnd, HWND_TOP, 0, 0, 0, 0,
  240.             SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
  241.  
  242.     for (winPtr = ((TkWindow*)tkwin)->nextPtr; winPtr != NULL;
  243.      winPtr = winPtr->nextPtr) {
  244.     if ((winPtr->window != None) && !(winPtr->flags & TK_TOP_LEVEL)) {
  245.         TkWinSetWindowPos(scrollPtr->hwnd, Tk_GetHWND(winPtr->window),
  246.             Below);
  247.         break;
  248.     }
  249.     }
  250.  
  251.     scrollPtr->lastVertical = scrollPtr->info.vertical;
  252.     scrollPtr->oldProc = (WNDPROC)SetWindowLong(scrollPtr->hwnd, GWL_WNDPROC,
  253.         (DWORD) ScrollbarProc);
  254.     window = Tk_AttachHWND(tkwin, scrollPtr->hwnd);
  255.  
  256.     UpdateScrollbar(scrollPtr);
  257.     return window;
  258. }
  259.  
  260. /*
  261.  *--------------------------------------------------------------
  262.  *
  263.  * TkpDisplayScrollbar --
  264.  *
  265.  *    This procedure redraws the contents of a scrollbar window.
  266.  *    It is invoked as a do-when-idle handler, so it only runs
  267.  *    when there's nothing else for the application to do.
  268.  *
  269.  * Results:
  270.  *    None.
  271.  *
  272.  * Side effects:
  273.  *    Information appears on the screen.
  274.  *
  275.  *--------------------------------------------------------------
  276.  */
  277.  
  278. void
  279. TkpDisplayScrollbar(clientData)
  280.     ClientData clientData;    /* Information about window. */
  281. {
  282.     WinScrollbar *scrollPtr = (WinScrollbar *) clientData;
  283.     Tk_Window tkwin = scrollPtr->info.tkwin;
  284.  
  285.     scrollPtr->info.flags &= ~REDRAW_PENDING;
  286.     if ((tkwin == NULL) || !Tk_IsMapped(tkwin)) {
  287.     return;
  288.     }
  289.  
  290.     /*
  291.      * Destroy and recreate the scrollbar control if the orientation
  292.      * has changed.
  293.      */
  294.  
  295.     if (scrollPtr->lastVertical != scrollPtr->info.vertical) {
  296.     HWND hwnd = Tk_GetHWND(Tk_WindowId(tkwin));
  297.  
  298.     SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) scrollPtr->oldProc);
  299.     DestroyWindow(hwnd);
  300.  
  301.     CreateProc(tkwin, Tk_WindowId(Tk_Parent(tkwin)),
  302.         (ClientData) scrollPtr);
  303.     } else {
  304.     UpdateScrollbar(scrollPtr);
  305.     }
  306. }
  307.  
  308. /*
  309.  *----------------------------------------------------------------------
  310.  *
  311.  * TkpDestroyScrollbar --
  312.  *
  313.  *    Free data structures associated with the scrollbar control.
  314.  *
  315.  * Results:
  316.  *    None.
  317.  *
  318.  * Side effects:
  319.  *    Restores the default control state.
  320.  *
  321.  *----------------------------------------------------------------------
  322.  */
  323.  
  324. void
  325. TkpDestroyScrollbar(scrollPtr)
  326.     TkScrollbar *scrollPtr;
  327. {
  328.     WinScrollbar *winScrollPtr = (WinScrollbar *)scrollPtr;
  329.     HWND hwnd = winScrollPtr->hwnd;
  330.     if (hwnd) {
  331.     SetWindowLong(hwnd, GWL_WNDPROC, (DWORD) winScrollPtr->oldProc);
  332.     if (winScrollPtr->winFlags & IN_MODAL_LOOP) {
  333.         ((TkWindow *)scrollPtr->tkwin)->flags |= TK_DONT_DESTROY_WINDOW;
  334.         SetParent(hwnd, NULL);
  335.     }
  336.     }
  337.     winScrollPtr->winFlags |= ALREADY_DEAD;
  338. }
  339.  
  340. /*
  341.  *----------------------------------------------------------------------
  342.  *
  343.  * UpdateScrollbarMetrics --
  344.  *
  345.  *    This function retrieves the current system metrics for a
  346.  *    scrollbar.
  347.  *
  348.  * Results:
  349.  *    None.
  350.  *
  351.  * Side effects:
  352.  *    Updates the geometry cache info for all scrollbars.
  353.  *
  354.  *----------------------------------------------------------------------
  355.  */
  356.  
  357. void
  358. UpdateScrollbarMetrics()
  359. {
  360.     Tk_ConfigSpec *specPtr;
  361.  
  362.     hArrowWidth = GetSystemMetrics(SM_CXHSCROLL);
  363.     hThumb = GetSystemMetrics(SM_CXHTHUMB);
  364.     vArrowWidth = GetSystemMetrics(SM_CXVSCROLL);
  365.     vArrowHeight = GetSystemMetrics(SM_CYVSCROLL);
  366.     vThumb = GetSystemMetrics(SM_CYVTHUMB);
  367.  
  368.     sprintf(defWidth, "%d", vArrowWidth);
  369.     for (specPtr = tkpScrollbarConfigSpecs; specPtr->type != TK_CONFIG_END;
  370.         specPtr++) {
  371.     if (specPtr->offset == Tk_Offset(TkScrollbar, width)) {
  372.         specPtr->defValue = defWidth;
  373.     }
  374.     }
  375. }
  376.  
  377. /*
  378.  *----------------------------------------------------------------------
  379.  *
  380.  * TkpComputeScrollbarGeometry --
  381.  *
  382.  *    After changes in a scrollbar's size or configuration, this
  383.  *    procedure recomputes various geometry information used in
  384.  *    displaying the scrollbar.
  385.  *
  386.  * Results:
  387.  *    None.
  388.  *
  389.  * Side effects:
  390.  *    The scrollbar will be displayed differently.
  391.  *
  392.  *----------------------------------------------------------------------
  393.  */
  394.  
  395. void
  396. TkpComputeScrollbarGeometry(scrollPtr)
  397.     register TkScrollbar *scrollPtr;    /* Scrollbar whose geometry may
  398.                      * have changed. */
  399. {
  400.     int fieldLength, minThumbSize;
  401.  
  402.     /*
  403.      * Windows doesn't use focus rings on scrollbars, but we still
  404.      * perform basic sanity checks to appease backwards compatibility.
  405.      */
  406.  
  407.     if (scrollPtr->highlightWidth < 0) {
  408.     scrollPtr->highlightWidth = 0;
  409.     }
  410.  
  411.     if (scrollPtr->vertical) {
  412.     scrollPtr->arrowLength = vArrowHeight;
  413.     fieldLength = Tk_Height(scrollPtr->tkwin);
  414.     minThumbSize = vThumb;
  415.     } else {
  416.     scrollPtr->arrowLength = hArrowWidth;
  417.     fieldLength = Tk_Width(scrollPtr->tkwin);
  418.     minThumbSize = hThumb;
  419.     }
  420.     fieldLength -= 2*scrollPtr->arrowLength;
  421.     if (fieldLength < 0) {
  422.     fieldLength = 0;
  423.     }
  424.     scrollPtr->sliderFirst = (int) ((double)fieldLength
  425.         * scrollPtr->firstFraction);
  426.     scrollPtr->sliderLast = (int) ((double)fieldLength
  427.         * scrollPtr->lastFraction);
  428.  
  429.     /*
  430.      * Adjust the slider so that some piece of it is always
  431.      * displayed in the scrollbar and so that it has at least
  432.      * a minimal width (so it can be grabbed with the mouse).
  433.      */
  434.  
  435.     if (scrollPtr->sliderFirst > fieldLength) {
  436.     scrollPtr->sliderFirst = fieldLength;
  437.     }
  438.     if (scrollPtr->sliderFirst < 0) {
  439.     scrollPtr->sliderFirst = 0;
  440.     }
  441.     if (scrollPtr->sliderLast < (scrollPtr->sliderFirst
  442.         + minThumbSize)) {
  443.     scrollPtr->sliderLast = scrollPtr->sliderFirst + minThumbSize;
  444.     }
  445.     if (scrollPtr->sliderLast > fieldLength) {
  446.     scrollPtr->sliderLast = fieldLength;
  447.     }
  448.     scrollPtr->sliderFirst += scrollPtr->arrowLength;
  449.     scrollPtr->sliderLast += scrollPtr->arrowLength;
  450.  
  451.     /*
  452.      * Register the desired geometry for the window (leave enough space
  453.      * for the two arrows plus a minimum-size slider, plus border around
  454.      * the whole window, if any).  Then arrange for the window to be
  455.      * redisplayed.
  456.      */
  457.  
  458.     if (scrollPtr->vertical) {
  459.     Tk_GeometryRequest(scrollPtr->tkwin,
  460.         scrollPtr->width, 2*scrollPtr->arrowLength + minThumbSize);
  461.     } else {
  462.     Tk_GeometryRequest(scrollPtr->tkwin,
  463.         2*scrollPtr->arrowLength + minThumbSize, scrollPtr->width);
  464.     }
  465.     Tk_SetInternalBorder(scrollPtr->tkwin, 0);
  466. }
  467.  
  468. /*
  469.  *----------------------------------------------------------------------
  470.  *
  471.  * ScrollbarProc --
  472.  *
  473.  *    This function is call by Windows whenever an event occurs on
  474.  *    a scrollbar control created by Tk.
  475.  *
  476.  * Results:
  477.  *    Standard Windows return value.
  478.  *
  479.  * Side effects:
  480.  *    May generate events.
  481.  *
  482.  *----------------------------------------------------------------------
  483.  */
  484.  
  485. static LRESULT CALLBACK
  486. ScrollbarProc(hwnd, message, wParam, lParam)
  487.     HWND hwnd;
  488.     UINT message;
  489.     WPARAM wParam;
  490.     LPARAM lParam;
  491. {
  492.     LRESULT result;
  493.     POINT point;
  494.     WinScrollbar *scrollPtr;
  495.     Tk_Window tkwin = Tk_HWNDToWindow(hwnd);
  496.  
  497.     if (tkwin == NULL) {
  498.     panic("ScrollbarProc called on an invalid HWND");
  499.     }
  500.     scrollPtr = (WinScrollbar *)((TkWindow*)tkwin)->instanceData;
  501.  
  502.     switch(message) {
  503.     case WM_HSCROLL:
  504.     case WM_VSCROLL: {
  505.         Tcl_Interp *interp;
  506.         Tcl_DString cmdString;
  507.         int command = LOWORD(wParam);
  508.         int code;
  509.  
  510.         GetCursorPos(&point);
  511.         Tk_TranslateWinEvent(NULL, WM_MOUSEMOVE, 0,
  512.             MAKELPARAM(point.x, point.y), &result);
  513.  
  514.         if (command == SB_ENDSCROLL) {
  515.         return 0;
  516.         }
  517.  
  518.         /*
  519.          * Bail out immediately if there isn't a command to invoke.
  520.          */
  521.  
  522.         if (scrollPtr->info.commandSize == 0) {
  523.         Tcl_ServiceAll();
  524.         return 0;
  525.         }
  526.         
  527.         Tcl_DStringInit(&cmdString);
  528.         Tcl_DStringAppend(&cmdString, scrollPtr->info.command,
  529.             scrollPtr->info.commandSize);
  530.         
  531.         if (command == SB_LINELEFT || command == SB_LINERIGHT) {
  532.         Tcl_DStringAppendElement(&cmdString, "scroll");
  533.         Tcl_DStringAppendElement(&cmdString,
  534.             (command == SB_LINELEFT ) ? "-1" : "1");
  535.         Tcl_DStringAppendElement(&cmdString, "units");
  536.         } else if (command == SB_PAGELEFT || command == SB_PAGERIGHT) {
  537.         Tcl_DStringAppendElement(&cmdString, "scroll");
  538.         Tcl_DStringAppendElement(&cmdString,
  539.             (command == SB_PAGELEFT ) ? "-1" : "1");
  540.         Tcl_DStringAppendElement(&cmdString, "pages");
  541.         } else {
  542.         char valueString[TCL_DOUBLE_SPACE];
  543.         double pos = 0.0;
  544.         switch (command) {
  545.             case SB_THUMBPOSITION:
  546.             pos = ((double)HIWORD(wParam)) / MAX_SCROLL;
  547.             break;
  548.  
  549.             case SB_THUMBTRACK:
  550.             pos = ((double)HIWORD(wParam)) / MAX_SCROLL;
  551.             break;
  552.  
  553.             case SB_TOP:
  554.             pos = 0.0;
  555.             break;
  556.  
  557.             case SB_BOTTOM:
  558.             pos = 1.0;
  559.             break;
  560.         }
  561.         sprintf(valueString, "%g", pos);
  562.         Tcl_DStringAppendElement(&cmdString, "moveto");
  563.         Tcl_DStringAppendElement(&cmdString, valueString);
  564.         }
  565.  
  566.         interp = scrollPtr->info.interp;
  567.         code = Tcl_GlobalEval(interp, cmdString.string);
  568.         if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) {
  569.         Tcl_AddErrorInfo(interp, "\n    (scrollbar command)");
  570.         Tcl_BackgroundError(interp);
  571.         }        
  572.         Tcl_DStringFree(&cmdString);        
  573.  
  574.         Tcl_ServiceAll();
  575.         return 0;
  576.     }
  577.  
  578.     default:
  579.         if (Tk_TranslateWinEvent(hwnd, message, wParam, lParam, &result)) {
  580.         return result;
  581.         }
  582.     }
  583.     return CallWindowProc(scrollPtr->oldProc, hwnd, message, wParam, lParam);
  584. }
  585.  
  586. /*
  587.  *----------------------------------------------------------------------
  588.  *
  589.  * TkpConfigureScrollbar --
  590.  *
  591.  *    This procedure is called after the generic code has finished
  592.  *    processing configuration options, in order to configure
  593.  *    platform specific options.
  594.  *
  595.  * Results:
  596.  *    None.
  597.  *
  598.  * Side effects:
  599.  *    None.
  600.  *
  601.  *----------------------------------------------------------------------
  602.  */
  603.  
  604. void
  605. TkpConfigureScrollbar(scrollPtr)
  606.     register TkScrollbar *scrollPtr;    /* Information about widget;  may or
  607.                      * may not already have values for
  608.                      * some fields. */
  609. {
  610. }
  611.  
  612. /*
  613.  *--------------------------------------------------------------
  614.  *
  615.  * ScrollbarBindProc --
  616.  *
  617.  *    This procedure is invoked when the default <ButtonPress>
  618.  *    binding on the Scrollbar bind tag fires.
  619.  *
  620.  * Results:
  621.  *    None.
  622.  *
  623.  * Side effects:
  624.  *    The event enters a modal loop.
  625.  *
  626.  *--------------------------------------------------------------
  627.  */
  628.  
  629. static int
  630. ScrollbarBindProc(clientData, interp, eventPtr, tkwin, keySym)
  631.     ClientData clientData;
  632.     Tcl_Interp *interp;
  633.     XEvent *eventPtr;
  634.     Tk_Window tkwin;
  635.     KeySym keySym;
  636. {
  637.     TkWindow *winPtr = (TkWindow*)tkwin;
  638.     if (eventPtr->type == ButtonPress) {
  639.     winPtr->flags |= TK_DEFER_MODAL;
  640.     }
  641.     return TCL_OK;
  642. }
  643.  
  644. /*
  645.  *----------------------------------------------------------------------
  646.  *
  647.  * ModalLoopProc --
  648.  *
  649.  *    This function is invoked at the end of the event processing
  650.  *    whenever the ScrollbarBindProc has been invoked for a ButtonPress
  651.  *    event. 
  652.  *
  653.  * Results:
  654.  *    None.
  655.  *
  656.  * Side effects:
  657.  *    Enters a modal loop.
  658.  *
  659.  *----------------------------------------------------------------------
  660.  */
  661.  
  662. static void
  663. ModalLoopProc(tkwin, eventPtr)
  664.     Tk_Window tkwin;
  665.     XEvent *eventPtr;
  666. {
  667.     TkWindow *winPtr = (TkWindow*)tkwin;
  668.     WinScrollbar *scrollPtr = (WinScrollbar *) winPtr->instanceData;
  669.     int oldMode;
  670.  
  671.     Tcl_Preserve((ClientData)scrollPtr);
  672.     scrollPtr->winFlags |= IN_MODAL_LOOP;
  673.     oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  674.     TkWinResendEvent(scrollPtr->oldProc, scrollPtr->hwnd, eventPtr);
  675.     (void) Tcl_SetServiceMode(oldMode);
  676.     scrollPtr->winFlags &= ~IN_MODAL_LOOP;
  677.     if (scrollPtr->hwnd && scrollPtr->winFlags & ALREADY_DEAD) {
  678.     DestroyWindow(scrollPtr->hwnd);
  679.     }
  680.     Tcl_Release((ClientData)scrollPtr);
  681. }
  682.  
  683. /*
  684.  *--------------------------------------------------------------
  685.  *
  686.  * TkpScrollbarPosition --
  687.  *
  688.  *    Determine the scrollbar element corresponding to a
  689.  *    given position.
  690.  *
  691.  * Results:
  692.  *    One of TOP_ARROW, TOP_GAP, etc., indicating which element
  693.  *    of the scrollbar covers the position given by (x, y).  If
  694.  *    (x,y) is outside the scrollbar entirely, then OUTSIDE is
  695.  *    returned.
  696.  *
  697.  * Side effects:
  698.  *    None.
  699.  *
  700.  *--------------------------------------------------------------
  701.  */
  702.  
  703. int
  704. TkpScrollbarPosition(scrollPtr, x, y)
  705.     register TkScrollbar *scrollPtr;    /* Scrollbar widget record. */
  706.     int x, y;                /* Coordinates within scrollPtr's
  707.                      * window. */
  708. {
  709.     int length, width, tmp;
  710.  
  711.     if (scrollPtr->vertical) {
  712.     length = Tk_Height(scrollPtr->tkwin);
  713.     width = Tk_Width(scrollPtr->tkwin);
  714.     } else {
  715.     tmp = x;
  716.     x = y;
  717.     y = tmp;
  718.     length = Tk_Width(scrollPtr->tkwin);
  719.     width = Tk_Height(scrollPtr->tkwin);
  720.     }
  721.  
  722.     if ((x < scrollPtr->inset) || (x >= (width - scrollPtr->inset))
  723.         || (y < scrollPtr->inset) || (y >= (length - scrollPtr->inset))) {
  724.     return OUTSIDE;
  725.     }
  726.  
  727.     /*
  728.      * All of the calculations in this procedure mirror those in
  729.      * TkpDisplayScrollbar.  Be sure to keep the two consistent.
  730.      */
  731.  
  732.     if (y < (scrollPtr->inset + scrollPtr->arrowLength)) {
  733.     return TOP_ARROW;
  734.     }
  735.     if (y < scrollPtr->sliderFirst) {
  736.     return TOP_GAP;
  737.     }
  738.     if (y < scrollPtr->sliderLast) {
  739.     return SLIDER;
  740.     }
  741.     if (y >= (length - (scrollPtr->arrowLength + scrollPtr->inset))) {
  742.     return BOTTOM_ARROW;
  743.     }
  744.     return BOTTOM_GAP;
  745. }
  746.